﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace ForestFirePreventionGeography
{
    /// <summary>
    /// 角度事件参数
    /// </summary>
    class AngleEventArgs : EventArgs
    {
        /// <summary>
        /// 水平角，范围0~359
        /// </summary>
        public readonly short Horizon;
        /// <summary>
        /// 垂直角，范围-75~45
        /// </summary>
        public readonly short Vertical;
        public AngleEventArgs(short horizon, short vertical) { Horizon = horizon; Vertical = vertical; }
    }

    /// <summary>
    /// 地图设备元素
    ///     在地图上显示设备所在位置
    ///     显示设备当前监控的区域
    ///     显示录像当前监控的区域（附加功能）
    ///     显示报警所在位置，由AlarmAngle提供
    ///     打开视频按钮、打开录像按钮、
    ///     打开报警按钮、打开信息按钮
    ///     产生角度事件，用于控制云台移动到指定角度
    ///     显示巡航提示
    ///     显示录像提示
    ///     显示识别提示
    /// </summary>
    class DeviceElement
    {
        #region 公有事件
        public EventHandler OpenVideo;
        public EventHandler OpenRecord;
        public EventHandler OpenEvent;
        public EventHandler OpenInfo;
        public EventHandler<AngleEventArgs> GoAngle;
        #endregion

        #region 只读变量
        readonly int _MaxRadius = 100;
        readonly int _MinRadius = 10;
        #endregion

        #region 公有属性
        string area;
        public string Area { get { return area; } }

        string device;
        public string Device { get { return device; } }

        Point location;
        public Point Location { get { return location; } }

        uint high = 500;//云台高度，单位：米
        public uint High { get { return high; } }

        short videoHorizon = 0;
        public short VideoHorizon { get { return videoHorizon; } set { videoHorizon = value; } }
        short videoVertical = -30;
        public short VideoVertical { get { return videoVertical; } set { videoVertical = value; } }

        short recordHorizon = 0;
        public short RecordHorizon { get { return recordHorizon; } set { recordHorizon = value; } }
        short recordVertical = 330;
        public short RecordVertical { get { return recordVertical; } set { recordVertical = value; } }

        ushort zoom = 1;//镜头放大倍率
        public ushort Zoom { get { return zoom; } set { zoom = value; } }
        #endregion

        #region 状态属性
        bool isOpened = false;
        /// <summary>
        /// 是否开启视频
        /// </summary>
        public bool IsOpened { get { return isOpened; } set { isOpened = value; } }

        bool isRecording = false;
        /// <summary>
        /// 是否正在录像
        /// </summary>
        public bool IsRecording { get { return isRecording; } set { isRecording = value; } }

        bool isAnalyzing = false;
        /// <summary>
        /// 是否正在识别
        /// </summary>
        public bool IsAnalyzing { get { return isAnalyzing; } set { isAnalyzing = value; } }

        bool isCruising = false;
        /// <summary>
        /// 是否正在巡航
        /// </summary>
        public bool IsCruising { get { return isCruising; } set { isCruising = value; } }
        #endregion

        #region 私有变量
        FormMap parent;//地图窗体
        List<Point> AlarmAngle = new List<Point>();
        #endregion

        #region 公有方法
        /// <summary>
        /// 添加报警点
        /// </summary>
        /// <param name="point"></param>
        public void AddAlarm(Point point)
        {
            if (!this.AlarmAngle.Contains(point)) this.AlarmAngle.Add(point);
        }

        /// <summary>
        /// 移除报警点
        /// </summary>
        /// <param name="point"></param>
        public void RemoveAlarm(Point point)
        {
            if (this.AlarmAngle.Contains(point)) this.AlarmAngle.Remove(point);
        }
        #endregion

        #region 构造函数
        public DeviceElement(FormMap parent, string area, string device, Point location, uint high)
        {
            this.parent = parent;
            this.parent.Paint += new PaintEventHandler(parent_Paint);
            this.area = area;
            this.device = device;
            this.location = location;
            this.high = high;
            this._MaxRadius = (int)(high * 3 / this.parent.MapScale);
        }
        #endregion

        #region 事件函数
        void parent_Paint(object sender, PaintEventArgs e)
        {
            Graphics G = e.Graphics;
            G.SmoothingMode = SmoothingMode.AntiAlias;

            Point point = this.parent.MapToClient(this.location);
            float radius = _MaxRadius * this.parent.Times;

            //绘制背景
            RectangleF rectBack = new RectangleF(point.X - radius, point.Y - radius, radius * 2, radius * 2);
            G.FillEllipse(new SolidBrush(Color.FromArgb(100, Color.Yellow)), rectBack);
            G.DrawEllipse(new Pen(Color.Lime, 2f), rectBack);
            //绘制中心
            Rectangle rectCenter = new Rectangle(point.X - 5, point.Y - 5, 10, 10);
            G.FillEllipse(Brushes.Lime, rectCenter);

            DrawVideoRegion(G, point, this.high / this.parent.MapScale, this.videoHorizon, this.videoVertical, 3, this.parent.Times, Color.FromArgb(100, Color.Blue), Color.FromArgb(200, Color.Red));


        }
        #endregion

        #region 私有方法
        /// <summary>
        /// 绘制视频区域
        /// </summary>
        /// <param name="G">绘图表面</param>
        /// <param name="point">绘图中心坐标</param>
        /// <param name="high">云台高度</param>
        /// <param name="horizon">云台水平角</param>
        /// <param name="vertical">云台垂直角</param>
        /// <param name="zoom">镜头放大倍率</param>
        /// <param name="times">地图缩小率</param>
        /// <param name="colorDraw">边线颜色</param>
        /// <param name="colorFill">填充颜色</param>
        void DrawVideoRegion(Graphics G, Point point, float high, short horizon, short vertical, ushort zoom, float times, Color colorDraw, Color colorFill)
        {
            if (high == 0 || zoom == 0 || times == 0) return;

            //水平半视野范围
            float horizonHalfRange = (float)(Math.Atan2(352, 610 * zoom) * 180 / Math.PI);
            //垂直半视野范围
            float verticalHalfRange = (float)(Math.Atan2(288, 610 * zoom) * 180 / Math.PI);

            //水平起始角度
            float horizonBegin = horizon - horizonHalfRange;
            //水平终止角度
            float horizonEnd = horizon + horizonHalfRange;

            //垂直起始角度
            float verticalBegin = vertical - verticalHalfRange;
            //垂直终止角度
            float verticalEnd = vertical + verticalHalfRange;

            //视野水平内径
            float horizonRadiusIn = (float)(high / Math.Tan((-verticalBegin) * Math.PI / 180));
            if (horizonRadiusIn < _MinRadius) horizonRadiusIn = _MinRadius;
            horizonRadiusIn = Math.Min(_MaxRadius, Math.Max(_MinRadius, horizonRadiusIn));

            //视野水平外径
            float horizonRadiusOut = (float)(high / Math.Tan((360 - verticalEnd) * Math.PI / 180));
            if (horizonRadiusOut < horizonRadiusIn) horizonRadiusOut = _MaxRadius * 2;

            horizonRadiusOut = Math.Min(_MaxRadius * 2, Math.Max(_MinRadius, horizonRadiusOut));

            RectangleF rectIn = new RectangleF(
                point.X - horizonRadiusIn * times,
                point.Y - horizonRadiusIn * times,
                horizonRadiusIn * 2 * times,
                horizonRadiusIn * 2 * times);
            G.DrawEllipse(new Pen(colorDraw, 2f), rectIn);//内框

            GraphicsPath path = new GraphicsPath();
            path.AddArc(rectIn, horizonBegin, horizonHalfRange * 2);

            RectangleF rectOut = new RectangleF(
                point.X - horizonRadiusOut * times,
                point.Y - horizonRadiusOut * times,
                horizonRadiusOut * 2 * times,
                horizonRadiusOut * 2 * times);

            G.DrawEllipse(new Pen(colorDraw, 2f), rectOut);//外框
            path.AddArc(rectOut, horizonEnd, -horizonHalfRange * 2);

            path.CloseAllFigures();
            G.FillPath(new SolidBrush(colorFill), path);

        }
        #endregion
        
    }
}
